package com.example.devsa_platform.service.impl;

import co.elastic.clients.elasticsearch._types.aggregations.Aggregation;
import co.elastic.clients.elasticsearch._types.aggregations.Buckets;
import co.elastic.clients.elasticsearch._types.aggregations.StringTermsBucket;
import com.example.devsa_platform.common.Result;
import com.example.devsa_platform.pojo.doc.ProfessionalDeveloperDoc;
import com.example.devsa_platform.pojo.vo.stats.ProfessionalDeveloperVo;
import com.example.devsa_platform.service.ProfessionalDeveloperService;
import jakarta.annotation.Resource;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchAggregations;
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.client.elc.NativeQuery;
import org.springframework.data.elasticsearch.core.AggregationsContainer;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

@Service
public class ProfessionalDeveloperImpl implements ProfessionalDeveloperService {
    @Resource
    private ElasticsearchTemplate template;

    @Override
    public Result<ProfessionalDeveloperVo> getProfessionalDeveloperStats() {
        NativeQuery query = NativeQuery.builder()
                .withAggregation("tBranchGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("t_branch.keyword")))
                )
                .withAggregation("iCorPMGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("i_cor_pm.keyword")))
                )
                .withAggregation("workExpGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("work_exp.keyword")))
                )
                .withAggregation("knowledge1Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_1.keyword")))
                )
                .withAggregation("knowledge2Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_2.keyword")))
                )
                .withAggregation("knowledge3Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_3.keyword")))
                )
                .withAggregation("knowledge4Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_4.keyword")))
                )
                .withAggregation("knowledge5Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_5.keyword")))
                )
                .withAggregation("knowledge6Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_6.keyword")))
                )
                .withAggregation("knowledge7Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_7.keyword")))
                )
                .withAggregation("knowledge8Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("knowledge_8.keyword")))
                )
                .withAggregation("frequency1Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("frequency_1.keyword")))
                )
                .withAggregation("frequency2Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("frequency_2.keyword")))
                )
                .withAggregation("frequency3Group", Aggregation.of(ag -> ag
                        .terms(te -> te.field("frequency_3.keyword")))
                )
                .withAggregation("timeSearchingGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("time_searching.keyword")))
                )
                .withAggregation("timeAnsweringGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("time_answering.keyword")))
                )
                .withAggregation("professionalTechGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("professional_tech.keyword")))
                )
                .withAggregation("industryGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("industry.keyword")))
                )
                .withAggregation("surveyLengthGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("survey_length.keyword")))
                )
                .withAggregation("surveyEaseGroup", Aggregation.of(ag -> ag
                        .terms(te -> te.field("survey_ease.keyword")))
                )
                .build();

        AggregationsContainer<?> aggregationsContainer = template.search(query, ProfessionalDeveloperDoc.class).getAggregations();
        ProfessionalDeveloperVo professionalDeveloperVo = null;

        if (aggregationsContainer instanceof ElasticsearchAggregations elasticsearchAggregations) {
            List<Map<String, Object>> tBranchGroup = parseAndAggregateResults("tBranchGroup", elasticsearchAggregations);
            List<Map<String, Object>> iCorPMGroup = parseAndAggregateResults("iCorPMGroup", elasticsearchAggregations);
            List<Map<String, Object>> workExpGroup = parseAndAggregateResults("workExpGroup", elasticsearchAggregations);
            List<Map<String, Object>> knowledge1Group = parseAndAggregateResults("knowledge1Group", elasticsearchAggregations);
            List<Map<String, Object>> knowledge2Group = parseAndAggregateResults("knowledge2Group", elasticsearchAggregations);
            List<Map<String, Object>> knowledge3Group = parseAndAggregateResults("knowledge3Group", elasticsearchAggregations);
            List<Map<String, Object>> knowledge4Group = parseAndAggregateResults("knowledge4Group", elasticsearchAggregations);
            List<Map<String, Object>> knowledge5Group = parseAndAggregateResults("knowledge5Group", elasticsearchAggregations);
            List<Map<String, Object>> knowledge6Group = parseAndAggregateResults("knowledge6Group", elasticsearchAggregations);
            List<Map<String, Object>> knowledge7Group = parseAndAggregateResults("knowledge7Group", elasticsearchAggregations);
            List<Map<String, Object>> knowledge8Group = parseAndAggregateResults("knowledge8Group", elasticsearchAggregations);
            List<Map<String, Object>> frequency1Group = parseAndAggregateResults("frequency1Group", elasticsearchAggregations);
            List<Map<String, Object>> frequency2Group = parseAndAggregateResults("frequency2Group", elasticsearchAggregations);
            List<Map<String, Object>> frequency3Group = parseAndAggregateResults("frequency3Group", elasticsearchAggregations);
            List<Map<String, Object>> timeSearchingGroup = parseAndAggregateResults("timeSearchingGroup", elasticsearchAggregations);
            List<Map<String, Object>> timeAnsweringGroup = parseAndAggregateResults("timeAnsweringGroup", elasticsearchAggregations);
            List<Map<String, Object>> professionalTechGroup = parseAndAggregateResults("professionalTechGroup", elasticsearchAggregations);
            List<Map<String, Object>> industryGroup = parseAndAggregateResults("industryGroup", elasticsearchAggregations);
            List<Map<String, Object>> surveyLengthGroup = parseAndAggregateResults("surveyLengthGroup", elasticsearchAggregations);
            List<Map<String, Object>> surveyEaseGroup = parseAndAggregateResults("surveyEaseGroup", elasticsearchAggregations);

            professionalDeveloperVo = new ProfessionalDeveloperVo(
                    tBranchGroup,
                    iCorPMGroup,
                    workExpGroup,
                    knowledge1Group,
                    knowledge2Group,
                    knowledge3Group,
                    knowledge4Group,
                    knowledge5Group,
                    knowledge6Group,
                    knowledge7Group,
                    knowledge8Group,
                    frequency1Group,
                    frequency2Group,
                    frequency3Group,
                    timeSearchingGroup,
                    timeAnsweringGroup,
                    professionalTechGroup,
                    industryGroup,
                    surveyLengthGroup,
                    surveyEaseGroup
            );
        }
        return Result.success(professionalDeveloperVo);
    }


    private List<Map<String, Object>> parseAndAggregateResults(String aggregationName, ElasticsearchAggregations elasticsearchAggregations) {
        Map<String, Long> aggregatedCounts = new HashMap<>();

        List<Map<String, Object>> originalResults = parseAggregation(aggregationName, elasticsearchAggregations);
        for (Map<String, Object> result : originalResults) {
            String key = (String) result.get("key");
            Long docCount = ((Number) result.get("doc_count")).longValue();

            // Split the key by ";"
            String[] parts = key.split(";");
            for (String part : parts) {
                part = part.trim();
                aggregatedCounts.put(part, aggregatedCounts.getOrDefault(part, 0L) + docCount);
            }
        }

        // Convert aggregatedCounts to the desired output
        List<Map<String, Object>> parsedResults = new ArrayList<>();
        for (Map.Entry<String, Long> entry : aggregatedCounts.entrySet()) {
            Map<String, Object> map = new HashMap<>();
            map.put("key", entry.getKey());
            map.put("doc_count", entry.getValue());
            parsedResults.add(map);
        }

        return parsedResults;
    }

    private List<Map<String, Object>> parseAggregation(String aggName, ElasticsearchAggregations elasticsearchAggregations) {
        Buckets<StringTermsBucket> buckets = Objects.requireNonNull(elasticsearchAggregations.get(aggName)).aggregation().getAggregate().sterms().buckets();
        return buckets.array().stream()
                .map(bucket -> {
                    String key = bucket.key().stringValue();
                    long docCount = bucket.docCount();
                    Map<String, Object> map = new HashMap<>();
                    map.put("key", key);
                    map.put("doc_count", docCount);
                    return map;
                })
                .collect(Collectors.toList());
    }
}
